/**
 *
 * @author DorcasBless
 * you can find the Synaxarium at http://code.google.com/p/synaxarium/
 * April, 2009
 * Version 1.0.0
 *
 * some code snippets were inspired from GoBible http://code.google.com/p/gobible
 *
 */
package com.christian;

import java.io.IOException;
import java.util.Calendar;
import java.util.Vector;
import javax.microedition.lcdui.*;

public class SynCanvas extends Canvas implements CommandListener {

    private int width,  y,  fontHeight,  height;
    private SynMIDlet synMIDlet;
    private boolean sameStory;
    private Vector pages = new Vector();
    private int currentPageNo;
    private int textWrap;
    private final static int TEXT_BORDER_RIGHT = 3;
    private int linesNum;
    private int pagesSize;
    private Command searchResults = new Command("\u0646\u062A\u0627\u0626\u062C \u0627\u0644\u0628\u062D\u062B", Command.SCREEN, 1);
    private Command searchByDateCommand = new Command("\u0628\u062D\u062B \u0628\u0627\u0644\u062A\u0627\u0631\u064A\u062E", Command.SCREEN, 1);
    private Command searchByNameCommand = new Command("\u0628\u062D\u062B \u0628\u0627\u0644\u0627\u0633\u0645", Command.SCREEN, 1);
    private Command nextCommand = new Command("\u0627\u0644\u064A\u0648\u0645 \u0627\u0644\u062A\u0627\u0644\u0649", Command.SCREEN, 0);
    private Command previousCommand = new Command("\u0627\u0644\u064A\u0648\u0645 \u0627\u0644\u0633\u0627\u0628\u0642", Command.SCREEN, 0);
    private Command sendSMSCommand;
    private Command prefsCommand = new Command("\u0627\u0644\u0627\u062E\u062A\u064A\u0627\u0631\u0627\u062A", Command.SCREEN, 1);
    private Command aboutCommand = new Command("\u0639\u0646 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C", Command.SCREEN, 1);
    private Command exitCommand = new Command("\u062E\u0631\u0648\u062C", Command.EXIT, 1);
    private int lastSpaceIndex = 0,  lineStartIndex = 0;

    // When scrolling through a Synaxarium story, it is handy to keep a record of
    // the lines for each scroll point. This saves having to
    // rewrap all lines up to the current scroll point.
    private int[] scrollPoints = new int[100];
    private boolean pageEnd;
    private int currentScrollPointIndex = 0;
    // Colours
    public int textColour = 0x000000;
    public int backColour = 0xFFFFFF;
    public int highlightColour = 0xE0E0FF;
    private String copticDate;

    public void setCurrentPageNo(int currentPageNo) {
        this.currentPageNo = currentPageNo;
    }

    public SynCanvas(SynMIDlet synMIDlet) {
        this.synMIDlet = synMIDlet;
        addCommands();
    }

    /* returns boolean to indicate success of the operation*/
    public boolean init(String fileName) {
        currentPageNo = 0;
        String text;
        try {
            text = FileReader.readText(fileName, synMIDlet);
            pages.setSize(0);
            setCopticDate(FileReader.fillPage(pages, text));
            pagesSize = pages.size();
            scrollPoints[0] = 0;
            return true;
        } catch (IOException ex) {
            synMIDlet.getAlertWarn().setString("\u0647\u0630\u0627 \u0627\u0644\u064A\u0648\u0645 \u063A\u064A\u0631 \u0645\u062A\u0648\u0627\u0641\u0631");
            synMIDlet.showWarnAlert();
        }
        return false;
    }

    public void paint(Graphics g) {

        width = getWidth();
        height = getHeight();
        textWrap = width - TEXT_BORDER_RIGHT;

        //for title
        if (sameStory == false) {
            Font boldFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Constatnts.FONT_SIZE_MAP[synMIDlet.fontSize]);
            fontHeight = boldFont.getHeight();
            g.setFont(boldFont);
            y = 0;
            linesNum = 0;
            wrapCheck(((Page) pages.elementAt(currentPageNo)).getTitle().toCharArray(), g, boldFont, true);
            y = linesNum * fontHeight + 4;
        } else {
            // for scrolling without the title
            y = 0;
        }

        //for story
        Font plainFont = Font.getFont(Font.FACE_SYSTEM, synMIDlet.fontStyle, Constatnts.FONT_SIZE_MAP[synMIDlet.fontSize]);
        fontHeight = plainFont.getHeight();
        g.setFont(plainFont);

        g.setColor(backColour);
        g.fillRect(0, y, width, height);
        g.setColor(textColour);
        y = y + 3;
        wrapCheck(((Page) pages.elementAt(currentPageNo)).getSubject().toCharArray(), g, plainFont, false);

    }

    public void keyPressed(int keyCode) {
        int gameAction = getGameAction(keyCode);

        if (gameAction == DOWN) {
            sameStory = true;
            if (pageEnd == false) {
                currentScrollPointIndex++;
                scrollPoints[currentScrollPointIndex] = lineStartIndex;
                repaint();
                serviceRepaints();
            }
        } else if (gameAction == UP) {

            if (currentScrollPointIndex == 1) {
                sameStory = false;
                pageEnd = false;
                currentScrollPointIndex--;
                repaint();
                serviceRepaints();
            } else if (currentScrollPointIndex > 1) {
                sameStory = true;
                pageEnd = false;
                currentScrollPointIndex--;
                repaint();
                serviceRepaints();
            }

        } else if (gameAction == RIGHT) {
            if (currentPageNo < pagesSize - 1) {
                sameStory = false;
                currentScrollPointIndex = 0;
                pageEnd = false;
                currentPageNo++;
                repaint();
                serviceRepaints();
            }
        } else if (gameAction == LEFT) {
            if (currentPageNo > 0) {
                sameStory = false;
                currentScrollPointIndex = 0;
                pageEnd = false;
                currentPageNo--;
                repaint();
                serviceRepaints();
            }
        }
    }

    /**
     * Checks if the line needs to be wrapped and wraps if necessary.
     */
    private void wrapCheck(char[] text, Graphics g, Font font, boolean title) {


        int index = 0, textLen = text.length;
        lineStartIndex = scrollPoints[currentScrollPointIndex];

        // calculate the total width of the story/title
        int lineWidth = font.charsWidth(text, 0, textLen);
        char currentChar;

        if (lineWidth >= textWrap) {

            // loop on all the characters of the story/title text
            for (index = lineStartIndex; index < textLen && (y + fontHeight) <= height; index++) {
                currentChar = text[index];
                if (currentChar == ' ') {
                    lastSpaceIndex = index;
                }

                // calculate line length so far
                lineWidth = font.charsWidth(text, lineStartIndex, (index - lineStartIndex) + 1);

                // in case the line width exceeded the screen width;
                if (lineWidth >= textWrap) {
                    // in case that the text belongs to title, a fillrect will be called for each wrapped line
                    if (title == true) {
                        g.setColor(highlightColour);
                        g.fillRect(0, y, width, fontHeight);
                        g.setColor(textColour);
                        linesNum++;
                    }
                    g.drawChars(text, lineStartIndex, (lastSpaceIndex - lineStartIndex), textWrap, y, Graphics.RIGHT | Graphics.TOP);
                    y = y + fontHeight;
                    lineStartIndex = lastSpaceIndex + 1;
                }
            }
        }

        // no wrap for title for S40 issue
        if (title == true) {
            g.setColor(highlightColour);
            g.fillRect(0, y, width, fontHeight + 4);
            g.setColor(textColour);
            linesNum++;
            g.drawChars(text, lineStartIndex, (textLen - lineStartIndex), textWrap, y, Graphics.RIGHT | Graphics.TOP);
        }

        // no wrap for story text
        if (lineWidth < textWrap) {
            if (title != true) {
                pageEnd = true;
                g.drawChars(text, lineStartIndex, (textLen - lineStartIndex), textWrap, y, Graphics.RIGHT | Graphics.TOP);
            }
        }
    }

    public void addCommands() {

        addCommand(previousCommand);
        addCommand(nextCommand);
        addCommand(searchResults);
        addCommand(searchByDateCommand);
        addCommand(searchByNameCommand);


        //if midp 2.0
        if (Constatnts.MIDP20) {
            // Only add the send SMS command if the WMA API is supported
            try {
                Class.forName("javax.wireless.messaging.MessageConnection");
                sendSMSCommand = new Command("\u0627\u0631\u0633\u0644", Command.SCREEN, 0);
                addCommand(sendSMSCommand);
            } catch (ClassNotFoundException e) {
                // Okay we just won't create the command
            }
        }

        addCommand(prefsCommand);
        addCommand(aboutCommand);
        addCommand(exitCommand);

        // Set up the command listener
        setCommandListener(this);
    }

    public void commandAction(Command command, Displayable d) {
        switch (command.getCommandType()) {
            case Command.EXIT: {
                synMIDlet.exitMIDlet();
                break;
            }

            case Command.SCREEN: {
                if (command == prefsCommand) {
                    synMIDlet.showPrefsScreen();
                } else if (command == aboutCommand) {
                    synMIDlet.showAboutAlert();
                } else if (Constatnts.MIDP20 && command == sendSMSCommand) {
                    String currentStory = ((Page) pages.elementAt(currentPageNo)).getSubject();
                    //to avoid sending multiple sms
                    if (currentStory.length() > 160) {
                        currentStory = currentStory.substring(0, 159);
                        currentStory = currentStory.substring(0, currentStory.lastIndexOf('.'));
                    }
                    synMIDlet.showSendSMSScreen(currentStory);
                } else if (command == searchByDateCommand) {
                    synMIDlet.showSearchScreen();
                } else if (command == searchByNameCommand) {
                    synMIDlet.showSearchByNameCommand(false);
                } else if (command == previousCommand) {
                    currentPageNo = 0;
                    int prevDay = SynMIDlet.calendar.get(Calendar.DAY_OF_MONTH) - 1;
                    int currentMonth = SynMIDlet.calendar.get(Calendar.MONTH);
                    int currentYear = SynMIDlet.calendar.get(Calendar.YEAR);
                    if (prevDay == 0) {
                        if (currentMonth == 2) {
                            if (currentYear % 4 == 0) {
                                prevDay = 29;
                            } else {
                                prevDay = 28;
                            }
                        } //months with 31 days
                        else if (currentMonth == 0 || currentMonth == 3 || currentMonth == 5 || currentMonth == 7 || currentMonth == 8 || currentMonth == 10) {
                            prevDay = 31;
                        } else {
                            prevDay = 30;
                        }
                        currentMonth--;
                    }
                    SynMIDlet.calendar.set(Calendar.DAY_OF_MONTH, prevDay);
                    SynMIDlet.calendar.set(Calendar.MONTH, currentMonth);
                    if (synMIDlet.getCanvas().init(SynMIDlet.getCorrectDate(SynMIDlet.calendar.get(Calendar.YEAR), currentMonth + 1, prevDay))) {
                        synMIDlet.showNewMainScreen();
                    }
                } else if (command == nextCommand) {
                    currentPageNo = 0;
                    int nextDay = SynMIDlet.calendar.get(Calendar.DAY_OF_MONTH) + 1;
                    int currentMonth = SynMIDlet.calendar.get(Calendar.MONTH);
                    int currentYear = SynMIDlet.calendar.get(Calendar.YEAR);
                    if ((nextDay == 29 && currentMonth == 1 && !(currentYear % 4 == 0)) ||
                            (nextDay == 30 && currentMonth == 1 && (currentYear % 4 == 0)) ||
                            (nextDay == 31 && (currentMonth == 3 || currentMonth == 5 || currentMonth == 8 || currentMonth == 10)) ||
                            (nextDay == 32) && (currentMonth == 0 || currentMonth == 2 || currentMonth == 4 || currentMonth == 6 || currentMonth == 7 || currentMonth == 9 || currentMonth == 11)) {
                        nextDay = 1;
                        currentMonth++;
                    }

                    SynMIDlet.calendar.set(Calendar.DAY_OF_MONTH, nextDay);
                    SynMIDlet.calendar.set(Calendar.MONTH, currentMonth);

                    if (synMIDlet.getCanvas().init(SynMIDlet.getCorrectDate(SynMIDlet.calendar.get(Calendar.YEAR), currentMonth + 1, nextDay))) {
                        synMIDlet.showNewMainScreen();
                    }

                } else if (command == searchResults) {
                    synMIDlet.showSearchByNameCommand(true);
                }
                break;
            }
        }

    }

    /**
     * @return the copticDate
     */
    public String getCopticDate() {
        return copticDate;
    }

    /**
     * @param copticDate the copticDate to set
     */
    public void setCopticDate(String copticDate) {
        this.copticDate = copticDate;
    }

    public void fullUpdate() {
        sameStory = false;
        currentScrollPointIndex = 0;
        pageEnd = false;
        repaint();
        serviceRepaints();
    }

    public void updateGUI() {
        repaint();
        serviceRepaints();
    }
}